package org.jeecg.modules.basicShelf.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.basicCompartment.entity.BasicCompartment;
import org.jeecg.modules.basicCompartment.service.IBasicCompartmentService;
import org.jeecg.modules.basicShelf.entity.AdmissionShelvesVO;
import org.jeecg.modules.basicShelf.entity.BasicShelf;
import org.jeecg.modules.basicShelf.entity.BasicShelfVo;
import org.jeecg.modules.basicShelf.service.IBasicShelfService;
import org.jeecg.modules.basicShelfType.entity.BasicShelfType;
import org.jeecg.modules.basicShelfType.service.IBasicShelfTypeService;
import org.jeecg.modules.basicSkuInfo.entity.BasicSkuInfo;
import org.jeecg.modules.basicSkuInfo.service.IBasicSkuInfoService;
import org.jeecg.modules.inventory.entity.InventoryInfo;
import org.jeecg.modules.inventory.service.IInventoryInfoService;
import org.jeecg.modules.reportLabel.entity.ReportLabel;
import org.jeecg.modules.reportLabel.service.IReportLabelService;
import org.jeecg.modules.system.util.RMSUtil;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 货架表
 * @Author: jeecg-boot
 * @Date: 2023-11-01
 * @Version: V1.0
 */
@Api(tags = "货架表")
@RestController
@RequestMapping("/basicShelf/basicShelf")
@Slf4j
public class BasicShelfController extends JeecgController<BasicShelf, IBasicShelfService> {
    @Resource
    private IBasicShelfService basicShelfService;
    @Resource
    private IBasicShelfTypeService basicShelfTypeService;
    @Resource
    private IBasicCompartmentService compartmentService;
    @Resource
    private IBasicCompartmentService basicCompartmentService;
    @Resource
    private RMSUtil rmsUtil;
    @Resource
    private IReportLabelService reportLabelService;
    @Autowired
    private IBasicSkuInfoService basicSkuInfoService;
    @Autowired
    private IInventoryInfoService inventoryInfoService;

    /**
     * 分页列表查询
     *
     * @param basicShelf
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AutoLog(value = "货架-分页列表查询")
    @ApiOperation(value = "货架-分页列表查询", notes = "货架-分页列表查询")
    @GetMapping(value = "/list")
    public Result<?> queryPageList(BasicShelf basicShelf,
                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                   HttpServletRequest req) {
        QueryWrapper<BasicShelf> queryWrapper = QueryGenerator.initQueryWrapper(basicShelf, req.getParameterMap());
        Page<BasicShelf> page = new Page<BasicShelf>(pageNo, pageSize);
        IPage<BasicShelf> pageList = basicShelfService.page(page, queryWrapper);
        return Result.OK(pageList);
    }

    /**
     * 入库->呼叫货架：货架类型查询条件的下拉列表
     *
     * @param
     * @return
     */
    @AutoLog(value = "呼叫货架-货架类型下拉列表")
    @ApiOperation(value = "呼叫货架-货架类型下拉列表", notes = "呼叫货架-货架类型下拉列表")
    @PostMapping(value = "/getShelfTypeCodeList")
    public Result<?> getShelfTypeCodeList() {
        List<BasicShelfType> list = basicShelfTypeService.list(new LambdaQueryWrapper<BasicShelfType>().ne(BasicShelfType::getWarehouseCode, "G"));
        return Result.OK(list);
    }

    /**
     * 入库->呼叫货架：分页列表
     *
     * @param basicShelfVo
     * @param pageNo
     * @param pageSize
     * @return
     */
    @AutoLog(value = "呼叫货架-分页列表查询")
    @ApiOperation(value = "呼叫货架-分页列表查询", notes = "呼叫货架-分页列表查询")
    @GetMapping(value = "/listAGV")
    public Result<?> listAGV(BasicShelfVo basicShelfVo,
                             @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                             @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        LambdaQueryWrapper<BasicShelf> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(BasicShelf::getWarehouseCode, "G");
        if (StringUtils.isNotBlank(basicShelfVo.getSelectedSkuCode())) {
            // 从输入的内容中取出本次需要查询的品番编码
            String skuCode = null;
            List<BasicSkuInfo> basicSkuList = basicSkuInfoService.list();
            for (BasicSkuInfo skuDetail : basicSkuList) {
                if (basicShelfVo.getSelectedSkuCode().contains(skuDetail.getSkuCode())) {
                    skuCode = skuDetail.getSkuCode();
                }
            }
            Assert.notNull(skuCode, "查询的品番编码在基础数据品番列表中无对应的品番，请输入正确的品番编码查询！");

            // SELECT DISTINCT shelf_code FROM report_label WHERE (sku_code = ? AND available_box_quantity > 0)
            List<String> shelfCodes = reportLabelService.listBySkuCode(new LambdaQueryWrapper<ReportLabel>().eq(ReportLabel::getSkuCode, skuCode).gt(ReportLabel::getAvailableBoxQuantity, 0));
            if (CollectionUtils.isNotEmpty(shelfCodes)) {
                queryWrapper.in(BasicShelf::getShelfCode, shelfCodes);
            } else {
                return Result.OK(new Page<BasicShelf>());
            }
        }
        queryWrapper.like(StringUtils.isNotBlank(basicShelfVo.getShelfCode()), BasicShelf::getShelfCode, basicShelfVo.getShelfCode());
        queryWrapper.eq(StringUtils.isNotBlank(basicShelfVo.getShelfTypeCode()), BasicShelf::getShelfTypeCode, basicShelfVo.getShelfTypeCode());
        Page<BasicShelf> page = new Page<BasicShelf>(pageNo, pageSize);
        IPage<BasicShelf> pageList = basicShelfService.page(page, queryWrapper);
        pageList = this.calculationUseLayer(pageList);

        return Result.OK(pageList);
    }

    /**
     * 计算货架使用层数，先这么用着，后续会根据最大容积计算
     *
     * @param pageList
     * @return
     */
    private IPage<BasicShelf> calculationUseLayer(IPage<BasicShelf> pageList) {
        if (pageList.getPages() > 0) {
            List<BasicShelf> basicShelfList = pageList.getRecords();
            for (BasicShelf basicShelf : basicShelfList) {
                List<InventoryInfo> inventoryInfoList = inventoryInfoService.list(new LambdaQueryWrapper<InventoryInfo>()
                        .eq(InventoryInfo::getShelfCode, basicShelf.getShelfCode())
                        .gt(InventoryInfo::getAvailableBoxQuantity, 0));

                Set<Character> usedLayers = new HashSet<>();
                for (InventoryInfo inventoryInfo : inventoryInfoList) {
                    char layer = inventoryInfo.getCompartmentCode().charAt(9);
                    usedLayers.add(layer);
                }
                basicShelf.setUseLayer(usedLayers.size());
            }
            pageList.setRecords(basicShelfList);
        }
        return pageList;
    }

    @GetMapping("/getAll")
    public Result<?> getAll() {
        List<BasicShelf> list = basicShelfService.list();
        return Result.OK(list);
    }

    /**
     * 添加
     *
     * @param basicShelf
     * @return
     */
    @AutoLog(value = "货架-添加")
    @ApiOperation(value = "货架-添加", notes = "货架-添加")
    @PostMapping(value = "/add")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> add(@RequestBody BasicShelf basicShelf) {
        this.checkColumns(basicShelf);
        //1.0 添加货架
        BasicShelfType shelfType = basicShelfTypeService.getOne(new QueryWrapper<BasicShelfType>().eq("shelf_code", basicShelf.getShelfTypeCode()));
        Assert.notNull(shelfType, "货架类型数据异常,请联系管理员");
        basicShelf.setWarehouseCode(shelfType.getWarehouseCode());
        basicShelfService.save(basicShelf);
        //2.0 添加货格
        //同步生成对应的货格数据
        Integer plie = shelfType.getPlie();//层数
        Integer colums = shelfType.getColums();//每层格数
        Integer isTwoSided = shelfType.getIsTwoSided();//是否B/F面
        List<BasicCompartment> list = new ArrayList<>();
        int loopCount;
        if (isTwoSided == 1) {
            loopCount = plie * colums * 2;
        } else {
            loopCount = plie * colums;
        }
        for (int i = 0; i < loopCount; i++) {
            int layer = i / colums + 1;  // 计算当前层
            char position = (char) ('a' + i % colums);  // 计算当前位置，转换为字母
            String name = basicShelf.getShelfCode() + "F" + layer + "" + position;  // 组合名称，例如1a, 1b, 1c...
            BasicCompartment compartment = new BasicCompartment();
            // 判断当前循环是否大于 plie * colums
            if (i < plie * colums) {
                // 正面
                compartment.setCompartmentCode(name);
                compartment.setIsTwoSided("F");
            } else {
                // 反面
                name = basicShelf.getShelfCode() + "B" + (layer - plie) + "" + position;
                compartment.setCompartmentCode(name);
                compartment.setIsTwoSided("B");
            }
            compartment.setShelfCode(basicShelf.getShelfCode());
            compartment.setCompartmentUtilization(BigDecimal.ZERO);
            list.add(compartment);
        }
        compartmentService.saveBatch(list);//添加货格数据
        return Result.OK("添加成功！");
    }

    /**
     * 编辑
     *
     * @param basicShelf
     * @return
     */
    @AutoLog(value = "货架表-编辑")
    @ApiOperation(value = "货架表-编辑", notes = "货架表-编辑")
    @PutMapping(value = "/edit")
    public Result<?> edit(@RequestBody BasicShelf basicShelf) {
        this.checkColumns(basicShelf);
        basicShelfService.updateById(basicShelf);
        return Result.OK("编辑成功!");
    }

    public void checkColumns(BasicShelf basicShelf) {
        Assert.isTrue(StringUtils.isNotBlank(basicShelf.getShelfCode()), "请输入货架编码");
        Assert.isTrue(StringUtils.isNotBlank(basicShelf.getShelfName()), "请输入货架名称");
        Assert.isTrue(StringUtils.isNotBlank(basicShelf.getShelfTypeCode()), "请选择货架类型编码");
        Assert.notNull(basicShelf.getIsDenseShelving(), "请选择是否为密集货架");
//        Assert.isTrue(StringUtils.isNotBlank(basicShelf.getOldLocation()), "请输入老家位置");

        QueryWrapper<BasicShelf> queryWrapper = new QueryWrapper<>();
        queryWrapper.ne(null != basicShelf.getId(), "id", basicShelf.getId());
        queryWrapper.eq("shelf_code", basicShelf.getShelfCode());
        int repeatCount = basicShelfService.count(queryWrapper);
        Assert.isTrue(repeatCount == 0, "货架编码已存在");
    }

    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @AutoLog(value = "货架表-通过id删除")
    @ApiOperation(value = "货架表-通过id删除", notes = "货架表-通过id删除")
    @DeleteMapping(value = "/delete")
    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
        BasicShelf basicShelf = basicShelfService.getById(id);
        basicShelfService.removeById(id);
        LambdaQueryWrapper<BasicCompartment> lqw = Wrappers.lambdaQuery(BasicCompartment.class);
        lqw.eq(BasicCompartment::getShelfCode, basicShelf.getShelfCode());
        basicCompartmentService.remove(lqw);
        return Result.OK("删除成功!");
    }

    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @AutoLog(value = "货架表-批量删除")
    @ApiOperation(value = "货架表-批量删除", notes = "货架表-批量删除")
    @DeleteMapping(value = "/deleteBatch")
    public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
        List<BasicShelf> shelfList = basicShelfService.listByIds(Arrays.asList(ids.split(",")));
        this.basicShelfService.removeByIds(Arrays.asList(ids.split(",")));
        List<String> shelfCodeList = shelfList.stream().map(item -> {
            return item.getShelfCode();
        }).collect(Collectors.toList());
        LambdaQueryWrapper<BasicCompartment> lqw = Wrappers.lambdaQuery(BasicCompartment.class);
        lqw.in(BasicCompartment::getShelfCode, shelfCodeList);
        basicCompartmentService.remove(lqw);
        return Result.OK("批量删除成功!");
    }

    /**
     * 通过id查询
     *
     * @param id
     * @return
     */
    @AutoLog(value = "货架表-通过id查询")
    @ApiOperation(value = "货架表-通过id查询", notes = "货架表-通过id查询")
    @GetMapping(value = "/queryById")
    public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
        BasicShelf basicShelf = basicShelfService.getById(id);
        Assert.notNull(basicShelf, "货架类型数据异常,请联系管理员");
        return Result.OK(basicShelf);
    }

    /**
     * 导出excel
     *
     * @param request
     * @param basicShelf
     */
    @RequestMapping(value = "/exportXls")
    public ModelAndView exportXls(HttpServletRequest request, BasicShelf basicShelf) {
        return super.exportXls(request, basicShelf, BasicShelf.class, "货架表");
    }

    /**
     * 通过excel导入数据
     *
     * @param request
     * @param response
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
        long start = System.currentTimeMillis();

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile file = entity.getValue();// 获取上传文件对象
            ImportParams params = new ImportParams();
            params.setTitleRows(2);
            params.setHeadRows(1);
            params.setNeedSave(true);
            List<BasicShelf> basicShelves = new ArrayList<>();
            try {
                basicShelves = ExcelImportUtil.importExcel(file.getInputStream(), BasicShelf.class, params);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return Result.error("文件导入失败:" + e.getMessage());
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            for (BasicShelf basicShelf : basicShelves) {
                this.checkColumns(basicShelf);
                //1.0 添加货架
                BasicShelfType shelfType = basicShelfTypeService.getOne(new QueryWrapper<BasicShelfType>().eq("shelf_code", basicShelf.getShelfTypeCode()));
                Assert.notNull(shelfType, "货架类型数据异常,请联系管理员");
                basicShelf.setWarehouseCode(shelfType.getWarehouseCode());
                basicShelfService.save(basicShelf);
                //2.0 添加货格
                //同步生成对应的货格数据
                Integer plie = shelfType.getPlie();//层数
                Integer colums = shelfType.getColums();//每层格数
                Integer isTwoSided = shelfType.getIsTwoSided();//是否B/F面
                List<BasicCompartment> list = new ArrayList<>();
                int loopCount;
                if (isTwoSided == 1) {
                    loopCount = plie * colums * 2;
                } else {
                    loopCount = plie * colums;
                }
                for (int i = 0; i < loopCount; i++) {
                    int layer = i / colums + 1;  // 计算当前层
                    char position = (char) ('a' + i % colums);  // 计算当前位置，转换为字母
                    String name = basicShelf.getShelfCode() + "F" + layer + "" + position;  // 组合名称，例如1a, 1b, 1c...
                    BasicCompartment compartment = new BasicCompartment();
                    // 判断当前循环是否大于 plie * colums
                    if (i < plie * colums) {
                        // 正面
                        compartment.setCompartmentCode(name);
                        compartment.setIsTwoSided("F");
                    } else {
                        // 反面
                        name = basicShelf.getShelfCode() + "B" + (layer - plie) + "" + position;
                        compartment.setCompartmentCode(name);
                        compartment.setIsTwoSided("B");
                    }
                    compartment.setShelfCode(basicShelf.getShelfCode());
                    compartment.setCompartmentUtilization(BigDecimal.ZERO);
                    list.add(compartment);
                }
                compartmentService.saveBatch(list);//添加货格数据
            }

            log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
            return Result.ok("文件导入成功！数据行数：" + basicShelves.size());
        }
        return Result.error("文件导入失败！");

        //return super.importExcel(request, response, BasicShelf.class);
    }

    /**
     * 货架入场
     *
     * @param admissionShelvesVO
     * @return
     */
    @RequestMapping(value = "/admission", method = RequestMethod.POST)
    public Result<?> admission(@RequestBody AdmissionShelvesVO admissionShelvesVO) {
        JSONObject jsonObject = rmsUtil.enterShelf(admissionShelvesVO.getShelfCode(), admissionShelvesVO.getLocationCellCode(), admissionShelvesVO.getPlacementCellCode());
        int code = jsonObject.getJSONObject("response").getJSONObject("header").getIntValue("code");
        String msg = jsonObject.getJSONObject("response").getJSONObject("header").getString("msg");
        if (code != 0) {
            return Result.error(msg);
        }
        // 更新货架老家位置
        BasicShelf basicShelf = basicShelfService.getOne(new LambdaQueryWrapper<BasicShelf>().eq(BasicShelf::getShelfCode, admissionShelvesVO.getShelfCode()));
        basicShelf.setOldLocation(admissionShelvesVO.getPlacementCellCode());
        basicShelfService.updateById(basicShelf);
        return Result.OK();
    }

}
